package com.inspire.sms.service.impl;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse.SmsSendDetailDTO;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.google.gson.Gson;
import com.inspire.sms.constant.BaseResultEnum;
import com.inspire.sms.constant.Channels;
import com.inspire.sms.constant.Columns;
import com.inspire.sms.model.App;
import com.inspire.sms.model.BatchSmsTemplate;
import com.inspire.sms.model.Message;
import com.inspire.sms.model.Template;
import com.inspire.sms.exception.AmountNotEnoughException;
import com.inspire.sms.exception.BaseException;
import com.inspire.sms.exception.ChannelException;
import com.inspire.sms.model.dto.MessageDTO;
import com.inspire.sms.model.dto.QuerySendResult;
import com.inspire.sms.model.dto.SendMessageResult;
import com.inspire.sms.service.IChannelSMSService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

/**
 * 具体短信通道实现类 ---> 阿里通道
 */
@Service(Channels.ALI_SMS)
public class AliSMSServiceImpl implements IChannelSMSService {


	private static final String SUCCESS = "OK";

	private static final String LIMIT_CONTROL = "isv.BUSINESS_LIMIT_CONTROL";

	private static final String OUT_OF_SERVICE = "isv.OUT_OF_SERVICE";

	private static final String AMOUNT_NOT_ENOUGH = "isv.AMOUNT_NOT_ENOUGH";

	private static final Logger logger = LoggerFactory.getLogger(AliSMSServiceImpl.class);

	@Autowired
	private IAcsClient acsClient;

	@Override
	public SendMessageResult send(App app, Template template, MessageDTO message) throws ChannelException {
		//构建请求对象
		SendSmsRequest request = new SendSmsRequest();
		request.setMethod(MethodType.POST);
		request.setPhoneNumbers(message.getMobile());
		request.setSignName(app.getPrefix());
		request.setTemplateCode(template.getChannelTemplateNo());
		Map<String, Object> params = message.getParams();
		try {
			request.setTemplateParam(new ObjectMapper().writeValueAsString(params));
		} catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}
		SendSmsResponse sendSmsResponse;
		try {
			sendSmsResponse = acsClient.getAcsResponse(request);
		} catch (ClientException e) {
			throw new ChannelException(e);
		}
		checkChannelException(sendSmsResponse);
		if (SUCCESS.equals(sendSmsResponse.getCode())) {
			return new SendMessageResult(true, sendSmsResponse.getBizId());
		} else {
			logger.warn("阿里云通讯短信发送失败,原因:{},错误代码:{},请求Id:{}", sendSmsResponse.getMessage(), sendSmsResponse.getCode(),
					sendSmsResponse.getRequestId());
			return new SendMessageResult(sendSmsResponse.getCode());
		}
	}

	private void checkChannelException(SendSmsResponse sendSmsResponse) throws ChannelException {
		String code = sendSmsResponse.getCode();
		if (LIMIT_CONTROL.equals(code)) {
			throw new BaseException(BaseResultEnum.SEND_TOO_FREQUENTLY, "短信发送过于频繁," + sendSmsResponse.getMessage());
		} else if (OUT_OF_SERVICE.equals(code) || AMOUNT_NOT_ENOUGH.equals(code)) {
			throw new AmountNotEnoughException();
		}
	}

	@Override
	public QuerySendResult querySendStatus(App app, Message message) {
		try {
			QuerySendDetailsRequest request = new QuerySendDetailsRequest();
			// 必填-号码
			request.setPhoneNumber(message.getMobile());
			// 可选-调用发送短信接口时返回的BizId
			request.setBizId(message.getBizId());
			// 必填-短信发送的日期 支持30天内记录查询（可查其中一天的发送数据），格式yyyyMMdd
			request.setSendDate(new SimpleDateFormat("yyyyMMdd").format(message.getCreateDate()));
			// 必填-页大小
			request.setPageSize(1L);
			// 必填-当前页码从1开始计数
			request.setCurrentPage(1L);
			// hint 此处可能会抛出异常，注意catch
			QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
			// 获取返回结果
			if (SUCCESS.equals(querySendDetailsResponse.getCode())) {
				List<SmsSendDetailDTO> list = querySendDetailsResponse.getSmsSendDetailDTOs();
				if (CollectionUtils.isEmpty(list)) {
					if (Duration.between(message.getCreateDate().toInstant(), Instant.now()).toMinutes() > 5) {
						return new QuerySendResult(true, Columns.SendStatus.FAILURE, null, null, "noMatchSendRecord");
					} else {
						logger.info("未查询到对应的短信记录,可能是因为阿里读写库同步延迟");
						return new QuerySendResult(false);
					}
				}
				SmsSendDetailDTO smsSendDetailDTO = list.get(0);
				logger.info("阿里云通讯短信查询结果为:{}", new ObjectMapper().writeValueAsString(smsSendDetailDTO));
				int aliSendStatus = smsSendDetailDTO.getSendStatus().intValue();// 1：等待回执，2：发送失败，3：发送成功
				byte sendStatus = Columns.SendStatus.SENDING;
				Date receiveDate = null;
				String failCode = null;
				if (aliSendStatus == 2) {
					sendStatus = Columns.SendStatus.FAILURE;
					failCode = smsSendDetailDTO.getErrCode();
				} else if (aliSendStatus == 3) {
					receiveDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")// 2017-05-25 00:00:00
							.parse(smsSendDetailDTO.getReceiveDate());
					sendStatus = Columns.SendStatus.SUCCESS;
				}
				return new QuerySendResult(true, sendStatus, smsSendDetailDTO.getContent(), receiveDate,
						failCode);
			} else {
				return new QuerySendResult(false);
			}
		} catch (Exception e) {
			logger.error("阿里云通讯查询短信接口异常", e);
			return new QuerySendResult(false);
		}
	}

	@Override
	public SendMessageResult batchSend(App app, String[] mobile, String content) {
		//throw new UnsupportedOperationException();
		 final Gson gson = new Gson();
		final List<Map<String, String>> params = new ArrayList<Map<String, String>>();
		Map<String, String> param1  = new HashMap<>();
		param1.put("code", "1234");
		Map<String, String> param2  = new HashMap<>();
		param2.put("code", "4321");
		params.add(param1);
		params.add(param2);


		List<String> signList = new ArrayList<>();
		signList.add(app.getPrefix());
		signList.add(app.getPrefix());
		BatchSmsTemplate batchSmsTemplate = new BatchSmsTemplate();
		batchSmsTemplate.setPhoneNumbers(Arrays.asList(mobile));
		//batchSmsTemplate.setSignNames(Arrays.asList(app.getPrefix()));
		batchSmsTemplate.setSignNames(signList);
		batchSmsTemplate.setTemplateCode("SMS_167395359");
		batchSmsTemplate.setTemplateParams(params);

		Objects.requireNonNull(batchSmsTemplate);
		checkBatchSmsTemplate(batchSmsTemplate);

		final CommonRequest request = new CommonRequest();
		request.setSysMethod(MethodType.POST);
		request.setSysDomain("dysmsapi.aliyuncs.com");
		request.setSysVersion("2017-05-25");
		request.setSysAction("SendBatchSms");
		request.putQueryParameter("PhoneNumberJson", gson.toJson(batchSmsTemplate.getPhoneNumbers()));
		request.putQueryParameter("SignNameJson", gson.toJson(batchSmsTemplate.getSignNames()));
		request.putQueryParameter("TemplateCode", batchSmsTemplate.getTemplateCode());
		request.putQueryParameter("TemplateParamJson", gson.toJson(batchSmsTemplate.getTemplateParams()));

		System.out.println(gson.toJson(batchSmsTemplate.getPhoneNumbers()));
		System.out.println(gson.toJson(batchSmsTemplate.getTemplateParams()));
		System.out.println(gson.toJson(batchSmsTemplate.getSignNames()));
		System.out.println(gson.toJson(batchSmsTemplate.getTemplateCode()));
		/**
		 * 打印结果： 前面三个参数的个数必须一致
		 * ["15021468092","13661775772"]
		   [{"code":"1234"},{"code":"4321"}]
		   ["SoftStone","SoftStone"]
		   "SMS_167395359"
		 */

		Map<String, String> json = null;
		try {
			final CommonResponse response = this.acsClient.getCommonResponse(request);
			checkSmsResponse(response);

			json = gson.fromJson(response.getData(), Map.class);

		}
		catch (final ClientException e) {
			throw new RuntimeException(e);
		}

		if (SUCCESS.equals(json.get("Code"))) {
			return new SendMessageResult(true,json.get("BizId"));
		} else {
			logger.warn("阿里云通讯短信批量发送失败,原因:{},错误代码:{},请求Id:{}", json.get("Message"), json.get("Code"),
					json.get("RequestId"));
			return new SendMessageResult(json.get("Code"));
		}

	}

	/**
	 * 校验 BatchSmsTemplate.
	 * @param template
     */
	private void checkBatchSmsTemplate(final BatchSmsTemplate template) {

		checkNotEmpty(template.getSignNames().toString(), "BatchSmsTemplate signNames must be not empty");
		checkNotEmpty(template.getPhoneNumbers().toString(), "BatchSmsTemplate phoneNumbers must be not empty");
		checkNotEmpty(template.getTemplateCode(), "BatchSmsTemplate templateCode must be not empty");
		checkNotEmpty(template.getTemplateParams().toString(), "BatchSmsTemplate templateParams must be not empty");

		if (template.getSignNames().size() != template.getPhoneNumbers().size()
				&& template.getPhoneNumbers().size() != template.getTemplateParams().size()) {
			throw new IllegalArgumentException("BatchSmsTemplate phoneNumbers, signNames, templateParams size must be the same");
		}
	}

	/**
	 * 校验字符串不为空.
	 * @param str
	 * @param message
     */
	private void checkNotEmpty(final String str, final String message) {
		if (null == str || str.isEmpty()) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 校验 SendSmsResponse 状态.
	 * @param response
     */
	private void checkSmsResponse(final CommonResponse response) {
		if (null == response) {
			throw new RuntimeException("Response is null");
		}
		final Gson gson = new Gson();
		final Map<String, String> json = gson.fromJson(response.getData(), Map.class);
		if (!SUCCESS.equalsIgnoreCase(json.get("Code"))) {
			throw new RuntimeException("Http status: " + response.getHttpStatus() + ", response: " + response.getData());
		}
	}

	@Override
	public String getChannel() {
		return Channels.ALI_SMS;
	}

}